/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#include "uart.h"
#include <stdio.h>
#include "delay.h"
#include "arm_math.h"
#include <stdarg.h>
#include <string.h>
// #include "TMR_Configuration.h"
#include "at32f4xx.h"
#include "nvic.h"
SerialHandle_s serialHandle[serialCount] = {
	[serial1] = {
		.USARTx = USART1,
		.rxChannel = DMA1_Channel5,
		.txChannel = DMA1_Channel4,
		.packet.rxBufferSize = 0,
		.DMApacket.rxBufferSize = 0,
	},
	[serial2] = {
		.USARTx = USART2,
		.rxChannel = DMA1_Channel6,
		.txChannel = DMA1_Channel7,
		.packet.rxBufferSize = 0,
		.DMApacket.rxBufferSize = 0,
	},
	[serial3] = {
		.USARTx = USART3,
		.rxChannel = DMA1_Channel3,
		.txChannel = DMA1_Channel2,
		.packet.rxBufferSize = 0,
		.DMApacket.rxBufferSize = 0,
	},
	[serial4] = {
		.USARTx = UART4,
		.rxChannel = DMA2_Channel3,
		.txChannel = DMA2_Channel4,
		.packet.rxBufferSize = 0,
		.DMApacket.rxBufferSize = 0,
	},
	[serial5] = {
		.USARTx = UART5,
		.rxChannel = DMA2_Channel1,
		.txChannel = DMA2_Channel2,
		.packet.rxBufferSize = 0,
		.DMApacket.rxBufferSize = 0,
	},
};
void USART_DMA_SETUP(SerialHandle_s* serialx)
{
	USART_DMA_INIT(serialx->txChannel, (uint32_t) & (serialx->USARTx->DT), (uint32_t)(serialx->DMApacket.txBuffer), USART_MAX_BUFFER_SIZE, UART_TX);
	USART_DMA_INIT(serialx->rxChannel, (uint32_t) & (serialx->USARTx->DT), (uint32_t)(serialx->DMApacket.rxBuffer), USART_MAX_BUFFER_SIZE, UART_RX);
	// DMA_ChannelEnable(serialx->txChannel, ENABLE);
	DMA_ChannelEnable(serialx->rxChannel, ENABLE);
	/* Enable USARTx DMA Rx and TX request */
	USART_DMACmd(serialx->USARTx, USART_DMAReq_Rx, ENABLE);
	USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, ENABLE);

	if (serialx->USARTx == UART5)
	{
		// UART5_RX USE DMA flexible channel
		DMA_Flexible_Config(DMA2, Flex_Channel1, DMA_FLEXIBLE_UART5_RX);
		// uart_tx use dma flexible channel
		DMA_Flexible_Config(DMA2, Flex_Channel2, DMA_FLEXIBLE_UART5_TX);
	}
	else if (serialx->USARTx == UART4)
	{
		// UART5_RX USE DMA flexible channel
		DMA_Flexible_Config(DMA2, Flex_Channel3, DMA_FLEXIBLE_UART4_RX);
		// uart_tx use dma flexible channel
		DMA_Flexible_Config(DMA2, Flex_Channel4, DMA_FLEXIBLE_UART4_TX);
	}
}
void Serial_Begin(SerialHandle_s* serialx, uint32_t baudrate)
{
	Serial_Setup(serialx, baudrate, USART_WordLength_8b, USART_StopBits_1, USART_Parity_No, USART_Mode_Tx | USART_Mode_Rx, USART_HardwareFlowControl_None);
}
void USART_ClkCmd(USART_Type* USARTx, FunctionalState NewState)
{
	if (USARTx == USART1)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_USART1, NewState);
	}
	else if (USARTx == USART2)
	{
		RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_USART2, NewState);
	}
	else if (USARTx == USART3)
	{
		RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_USART3, NewState);
	}
	else if (USARTx == UART4)
	{
		RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_UART4, NewState);
	}
	else if (USARTx == UART5)
	{
		RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_UART5, NewState);
	}
}
void USART_NVIC_Cmd(USART_Type* USARTx, FunctionalState NewState)
{
	if (USARTx == USART1)
	{
		NVIC_Config(USART1_IRQn, 4, 1, NewState);
	}
	else if (USARTx == USART2)
	{
		NVIC_Config(USART2_IRQn, 4, 2, NewState);
	}
	else if (USARTx == USART3)
	{
		NVIC_Config(USART3_IRQn, 4, 3, NewState);
	}
	else if (USARTx == UART4)
	{
		NVIC_Config(UART4_IRQn, 4, 4, NewState);
	}
	else if (USARTx == UART5)
	{
		NVIC_Config(UART5_IRQn, 4, 5, NewState);
	}
}
void Serial_Setup(SerialHandle_s* serialx, uint32_t baudrate, uint16_t Wordlength, uint16_t Stopbits, uint16_t Parity, uint16_t Mode, uint16_t HardwareFlowControl)
{
	USART_Reset(serialx->USARTx);
	USART_ClkCmd(serialx->USARTx, ENABLE);
	USART_NVIC_Cmd(serialx->USARTx, ENABLE);
	USART_InitType USARTx_InitStructure;
	USARTx_InitStructure.USART_BaudRate = baudrate;
	USARTx_InitStructure.USART_WordLength = Wordlength;
	USARTx_InitStructure.USART_StopBits = Stopbits;
	USARTx_InitStructure.USART_Parity = Parity;
	USARTx_InitStructure.USART_Mode = Mode;
	USARTx_InitStructure.USART_HardwareFlowControl = HardwareFlowControl;
	USART_Init(serialx->USARTx, &USARTx_InitStructure);
	USART_DMA_SETUP(serialx);
	USART_INTConfig(serialx->USARTx, USART_INT_IDLEF, ENABLE);
	USART_INTConfig(serialx->USARTx, USART_INT_TRAC, ENABLE);
	USART_Cmd(serialx->USARTx, ENABLE);
}

// void Serial_printf(SerialHandle_s* USARTx, const char* format, ...)
// {

// 	char str[30];
// 	char c = 0;
// 	char ch = 0;
// 	va_list ap;
// 	va_start(ap, format); //???????????��?????????
// 	while ((c = *format))
// 	{
// 		switch (c)
// 		{
// 		case '%':
// 		{
// 			ch = *++format;

// 			switch (ch)
// 			{
// 			case 'b':
// 			{
// 				uint32_t n = va_arg(ap, int);
// 				myitoa(n, str, 2);
// 				Serial_puts(USARTx, str);
// 				break;
// 			}
// 			case 'c':
// 			{
// 				char c = va_arg(ap, int);
// 				Serial_putc(USARTx, c);
// 				break;
// 			}
// 			case 'd':
// 			{
// 				uint32_t n = va_arg(ap, int);
// 				myitoa(n, str, 10);
// 				Serial_puts(USARTx, str);
// 				break;
// 			}
// 			case 'x':
// 			{
// 				uint32_t n = va_arg(ap, int);
// 				myitoa(n, str, 16);
// 				Serial_puts(USARTx, str);
// 				break;
// 			}
// 			case 'f':
// 			{
// 				double f = va_arg(ap, double);
// 				uint32_t n;
// 				n = f;
// 				myitoa(n, str, 10);
// 				Serial_puts(USARTx, str);
// 				Serial_putc(USARTx, '.');
// 				n = (f - n) * 1000000;
// 				myitoa(n, str, 10);
// 				Serial_puts(USARTx, str);
// 				break;
// 			}
// 			case 's':
// 			{
// 				char* p = va_arg(ap, char*);
// 				Serial_puts(USARTx, p);
// 				break;
// 			}
// 			case '%':
// 			{
// 				Serial_putc(USARTx, '%');
// 				break;
// 			}
// 			default:
// 			{
// 				/*Serial_puts(USARTx, "#error:format invalid: <%");*/
// 				Serial_putc(USARTx, '%');
// 				Serial_putc(USARTx, ch);
// 				/*Serial_puts(USARTx, ">#");*/

// 				break;
// 			}
// 			}
// 		}
// 		break;
// 		default:
// 			Serial_putc(USARTx, c);
// 			break;
// 		}
// 		format++;
// 	}
// 	va_end(ap);
// }
// union floatHex
// {
// 	double f;
// 	uint8_t hex[8];
// }fhTmp;

// void hexFloatTest(double f)
// {
// 	char str[30];
// 	fhTmp.f = f;
// 	Serial_puts(&serialHandle[serial1], "Hex:");
// 	for (int i = 0;i < 8;i++)
// 	{
// 		Serial_putc(&serialHandle[serial1], '[');
// 		myitoa(fhTmp.hex[i], str, 16);
// 		Serial_puts(&serialHandle[serial1], str);
// 		Serial_putc(&serialHandle[serial1], ']');
// 		Serial_putc(&serialHandle[serial1], '\t');
// 	}
// 	Serial_puts(&serialHandle[serial1], "\n");
// }
// void uartPrintfloat(const char* format, ...)
// {
// 	char str[30];
// 	char c = 0;
// 	char ch = 0;
// 	bool catchFloat = 0;
// 	union _floatHex
// 	{
// 		double _f;
// 		uint8_t _u8;
// 		int8_t _i8;
// 		uint16_t _u16;
// 		int16_t _i16;
// 		uint32_t _u32;
// 		int32_t _i32;
// 		uint64_t _u64;
// 		int64_t _i64;
// 		uint8_t hex[8];
// 	}ftmp;
// 	va_list ap;
// 	va_start(ap, format);
// 	char *p = 0;
// 	while ((c = *format))
// 	{
// 		switch (c)
// 		{
// 		case '%':
// 			ch = *++format;
// 			switch (ch)
// 			{
// 			case 'd':
// 			{
// 				if(catchFloat)
// 				{
// 					p = va_arg(ap, char[8]);
// 					memcpy(&ftmp.hex[4],p,4);
// 				}
// 				else
// 				{
// 					p = va_arg(ap, char[8]);
// 					memcpy(&ftmp.hex[0],p,8);
// 				}
// 				myitoa(ftmp._i64, str, 10);
// 				Serial_puts(&serialHandle[serial1], str);
// 				break;
// 			}
// 			case 'f':

// 				if (!catchFloat)
// 				{
// 					catchFloat = 1;
// 					/**FIXME 第一次遇到浮点数据时，前面有4个不明字节数据, 跳过它！ */
// 					/**NOTE 不管什么类型都是8字节对齐的！ */
// 					p = va_arg(ap, char[8]);
// 					memcpy(ftmp.hex,&p[4],4);
// 				}
// 				p = va_arg(ap, char[8]);
// 				memcpy(&ftmp.hex[4],p,4);

// 				// hexFloatTest(f);
// 				int32_t n;
// 				n = ftmp._f;
// 				myitoa(n, str, 10);
// 				Serial_puts(&serialHandle[serial1], str);
// 				Serial_putc(&serialHandle[serial1], '.');
// 				n = (ftmp._f - n) * 1000000;
// 				if (n < 0)
// 					n = (unsigned)-n;
// 				myitoa(n, str, 10);
// 				Serial_puts(&serialHandle[serial1], str);
// 				memcpy(ftmp.hex,&p[4],4);
// 				break;
// 			case '%':
// 				Serial_putc(&serialHandle[serial1], '%');
// 				break;
// 			default:
// 				Serial_putc(&serialHandle[serial1], '%');
// 				Serial_putc(&serialHandle[serial1], ch);
// 				break;
// 			}
// 			break;
// 		default:
// 			Serial_putc(&serialHandle[serial1], c);
// 			break;
// 		}
// 		format++;
// 	}
// 	va_end(ap);
// 	Serial_flush(&serialHandle[serial1]);
// }
// void rt_kprintf(const char* format, ...)
// {

// 	char str[30];
// 	char c = 0;
// 	char ch = 0;
// 	bool catchFloat = 0;
// 	va_list ap;
// 	va_start(ap, format);
// 	while ((c = *format))
// 	{
// 		switch (c)
// 		{
// 		case '%':
// 		{
// 			ch = *++format;

// 			switch (ch)
// 			{
// 			case 'b':
// 			{
// 				uint32_t n = va_arg(ap, int);
// 				myitoa(n, str, 2);
// 				Serial_puts(&serialHandle[serial1], str);
// 				break;
// 			}
// 			case 'c':
// 			{
// 				char c = va_arg(ap, int);
// 				Serial_putc(&serialHandle[serial1], c);
// 				break;
// 			}
// 			case 'd':
// 			{
// 				uint32_t n = va_arg(ap, int);
// 				myitoa(n, str, 10);
// 				Serial_puts(&serialHandle[serial1], str);
// 				break;
// 			}
// 			case 'x':
// 			{
// 				uint32_t n = va_arg(ap, int);
// 				myitoa(n, str, 16);
// 				Serial_puts(&serialHandle[serial1], str);
// 				break;
// 			}
// 			case 'f':
// 			{
// 				if (!catchFloat)
// 				{
// 					catchFloat = 1;
// 					/**FIXME 第一次遇到浮点数据时，前面有4个不明字节数据, 跳过它！ */
// 					// int nn = va_arg(ap, char[4]);
// 					// Serial_puts(&serialHandle[serial1], "catchFloat:");
// 					// // hexFloatTest(*(double*)p);
// 					// myitoa(nn, str, 16);
// 					// Serial_puts(&serialHandle[serial1], str);
// 				}
// 				double f = va_arg(ap, double);
// 				hexFloatTest(f);
// 				int32_t n;
// 				n = f;
// 				myitoa(n, str, 10);
// 				Serial_puts(&serialHandle[serial1], str);
// 				Serial_putc(&serialHandle[serial1], '.');
// 				n = (f - n) * 1000000;
// 				if (n < 0)
// 					n = (unsigned)-n;
// 				myitoa(n, str, 10);
// 				Serial_puts(&serialHandle[serial1], str);
// 				break;
// 			}
// 			case 's':
// 			{
// 				char* p = va_arg(ap, char*);
// 				Serial_puts(&serialHandle[serial1], p);
// 				break;
// 			}
// 			case '%':
// 			{
// 				Serial_putc(&serialHandle[serial1], '%');
// 				break;
// 			}
// 			default:
// 			{
// 				/*Serial_puts(&serialHandle[serial1], "#error:format invalid: <%");*/
// 				Serial_putc(&serialHandle[serial1], '%');
// 				Serial_putc(&serialHandle[serial1], ch);
// 				/*Serial_puts(&serialHandle[serial1], ">#");*/

// 				break;
// 			}
// 			}
// 		}
// 		break;
// 		default:
// 			Serial_putc(&serialHandle[serial1], c);
// 			break;
// 		}
// 		format++;
// 	}
// 	va_end(ap);
// 	Serial_flush(&serialHandle[serial1]);
// }
// void usartPrintNum(double num)
// {
// 	Serial_printNum(&serialHandle[serial1], DEC, num, 0);
// }
// void usartPrintVariable(char* name, double value, bool _Not )
// {
// 	Serial_puts(&serialHandle[serial1], name);
// 	Serial_printNum(&serialHandle[serial1], DEC, value, _Not );
// 	Serial_flush(&serialHandle[serial1]);
// }

// void BLE_PrintVariable(char* name, double value, bool _Not , bool printNow)
// {
// 	Serial_puts(&serialHandle[serial4], name);
// 	Serial_printNum(&serialHandle[serial4], DEC, value, _Not );
// 	if (printNow)
// 		Serial_flush(&serialHandle[serial4]);
// }
// // printNum
// void Serial_printNum(SerialHandle_s* USARTx, uint8_t printType, double num, uint8_t Not )
// {
// 	int32_t IntNum = (int32_t)num; //ȡ��������
// 	char str[30];
// 	if (printType == DEC)
// 	{
// 		if (num < 0 && IntNum == 0) //���Ϸ��ţ���Ϊ��������Ϊ��ʱ�޷�֪������
// 		{
// 			Serial_putc(USARTx, '-');
// 		}

// 		Serial_printf(USARTx, "%d", IntNum);

// 		if (num - IntNum) //����С������
// 		{
// 			uint32_t temp = 0;
// 			uint8_t i = 0;
// 			Serial_putc(USARTx, '.');
// 			IntNum = (num - (double)IntNum) * 1000000;
// 			if (IntNum < 0)
// 			{
// 				IntNum = -IntNum;
// 			}
// 			temp = IntNum;

// 			while (1)
// 			{
// 				temp *= 10;
// 				if (temp > 1000000)
// 					break;
// 				i++;
// 				Serial_putc(USARTx, '0'); //С������油0
// 				if (i > 6)
// 					break;
// 			}
// 			Serial_printf(USARTx, "%d", IntNum);
// 		}
// 	}
// 	else if (printType == HEX)
// 	{
// 		myitoa(IntNum, str, HEX);
// 		Serial_puts(USARTx, str);
// 	}
// 	else if (printType == BIN)
// 	{
// 		myitoa(IntNum, str, BIN);
// 		Serial_puts(USARTx, str);
// 	}
// 	else if (printType == OCT)
// 	{
// 		myitoa(IntNum, str, OCT);
// 		Serial_puts(USARTx, str);
// 	}
// 	if (Not )
// 	{
// 		Serial_putc(USARTx, '\n');
// 	}
// 	else
// 	{
// 		Serial_putc(USARTx, '\t');
// 	}
// }
// void Serial_printf_test()
// {
// 	double a = 1.023546;
// 	Serial_printf(&serialHandle[serial], "%f\n", a);
// }
// char* myitoa(int num, char* str, int radix)
// { /*??????*/
// 	char index[] = "0123456789ABCDEF";
// 	unsigned unum; /*?��?????*/
// 	int i = 0, j, k;
// 	/*???unum???*/
// 	if (radix == 10 && num < 0) /*????????*/
// 	{
// 		unum = (unsigned)-num;
// 		str[i++] = '-';
// 	}
// 	else
// 		unum = (unsigned)num; /*????????*/
// 	/*???*/
// 	do
// 	{
// 		str[i++] = index[unum % (unsigned)radix];
// 		unum /= radix;
// 	} while (unum);
// 	str[i] = '\0';
// 	/*????*/
// 	if (str[0] == '-')
// 		k = 1; /*????????*/
// 	else
// 		k = 0;

// 	for (j = k; j <= (i - 1) / 2; j++)
// 	{
// 		char temp;
// 		temp = str[j];
// 		str[j] = str[i - 1 + k - j];
// 		str[i - 1 + k - j] = temp;
// 	}
// 	return str;
// }
void USART_DMA_INIT(DMA_Channel_Type* DMAchannelx, uint32_t periphAddr, uint32_t bufferAddr, uint16_t bufferSize, uint32_t Direction)
{
	DMA_InitType DMA_InitStructure;

	DMA_Reset(DMAchannelx);
	DMA_DefaultInitParaConfig(&DMA_InitStructure);
	DMA_InitStructure.DMA_PeripheralBaseAddr = periphAddr;
	DMA_InitStructure.DMA_MemoryBaseAddr = bufferAddr;
	DMA_InitStructure.DMA_Direction = Direction;
	DMA_InitStructure.DMA_BufferSize = bufferSize;
	DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;
	DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;
	DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_BYTE;
	DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE;
	DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;
	DMA_InitStructure.DMA_Priority = DMA_PRIORITY_LOW;
	DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;
	DMA_Init(DMAchannelx, &DMA_InitStructure);
}
void Serial_putc(SerialHandle_s* serialx, const char b)
{
	serialx->packet.txBuffer[serialx->packet.txBufferSize] = b;
	serialx->packet.txBufferSize++;
}
void Serial_puts(SerialHandle_s* serialx, const char* b)
{
	while (*b)
	{
		serialx->packet.txBuffer[serialx->packet.txBufferSize] = *b;
		serialx->packet.txBufferSize++;
		b++;
		if (serialx->packet.txBufferSize == USART_MAX_BUFFER_SIZE)
			Serial_flush(serialx);
	}
}
void Serial_put(SerialHandle_s* serialx, const char* buffer, uint16_t lenght)
{
	if (lenght + serialx->packet.txBufferSize > USART_MAX_BUFFER_SIZE)
	{
		uint16_t txSize = 0;
		txSize = USART_MAX_BUFFER_SIZE - serialx->packet.txBufferSize;
		memcpy(&(serialx->packet.txBuffer[serialx->packet.txBufferSize]), buffer, txSize);
		serialx->packet.txBufferSize = USART_MAX_BUFFER_SIZE;
		Serial_flush(serialx);
		memcpy(&(serialx->packet.txBuffer[0]), &buffer[txSize], lenght - txSize);
		serialx->packet.txBufferSize = lenght - txSize;
	}
	else
	{
		while (lenght)
		{
			serialx->packet.txBuffer[serialx->packet.txBufferSize] = *buffer;
			serialx->packet.txBufferSize++;
			buffer++;
			lenght--;
		}
	}
}
void dmaChannelFlush(SerialHandle_s* serialx)
{
	if (!serialx->packet.txBufferSize)
		return;
	/*wait for transmition complete*/
	uint16_t tryCount = 0;
	// delay_ms(10);
	while (serialx->DMApacket.status & txBusy)
	{
		delay_us(10);
		// rt_kprintf("userial busy!!\n");
		if (tryCount++ > SystemCoreClock / 1000000)
			return;
	}
	/*close dma channel and USART_DMAReq_Tx*/
	DMA_ChannelEnable(serialx->txChannel, DISABLE);
	USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, DISABLE);

	/*copy data from packet.txBuffer to DMApacket.txBuffer*/
	memcpy(serialx->DMApacket.txBuffer, serialx->packet.txBuffer, serialx->packet.txBufferSize);
	serialx->DMApacket.txBufferSize = serialx->packet.txBufferSize;
	/*reset packet.txBufferSize to 0*/
	serialx->packet.txBufferSize = 0;

	/*IrDA modulate for usart3*/
	// if (serialx->USARTx == USART3) IrDA_Modulate_Cmd(ENABLE);
	/*reset dma current data counter to DMApacket.txBufferSize*/
	DMA_SetCurrDataCounter(serialx->txChannel, serialx->DMApacket.txBufferSize);
	/*reopen USART_DMAReq_Tx*/
	USART_DMACmd(serialx->USARTx, USART_DMAReq_Tx, ENABLE);
	/*reopen dma channel*/
	DMA_ChannelEnable(serialx->txChannel, ENABLE);
	/*tx busy*/
	serialx->DMApacket.status |= txBusy;
}
void Serial_flush(SerialHandle_s* serialx)
{
	dmaChannelFlush(serialx);
}
void Serial_IRQHandler(SerialHandle_s* serialx)
{
	uint16_t bufferCount = 0;
	if (USART_GetITStatus(serialx->USARTx, USART_INT_IDLEF))
	{
		USART_ClearITPendingBit(serialx->USARTx, USART_INT_IDLEF);
		(void)(serialx->USARTx->DT);
		DMA_ChannelEnable(serialx->rxChannel, DISABLE);
		serialx->DMApacket.status |= rxDone;
		bufferCount = DMA_GetCurrDataCounter(serialx->rxChannel);
		serialx->DMApacket.rxBufferSize = USART_MAX_BUFFER_SIZE - bufferCount;
		if (serialx->packet.rxBufferSize >= USART_MAX_BUFFER_SIZE)
			serialx->packet.rxBufferSize = 0;
		memcpy(&serialx->packet.rxBuffer[serialx->packet.rxBufferSize], serialx->DMApacket.rxBuffer, serialx->DMApacket.rxBufferSize);
		serialx->packet.rxBufferSize += serialx->DMApacket.rxBufferSize;

		DMA_SetCurrDataCounter(serialx->rxChannel, USART_MAX_BUFFER_SIZE);
		DMA_ChannelEnable(serialx->rxChannel, ENABLE);
		USART_DMACmd(serialx->USARTx, USART_DMAReq_Rx, ENABLE);
	}
	if (USART_GetITStatus(serialx->USARTx, USART_INT_TRAC))
	{
		USART_ClearITPendingBit(serialx->USARTx, USART_INT_TRAC);
		/*turn off IrDA moudulate of usart3*/
		// if (serialx->USARTx == USART3) IrDA_Modulate_Cmd(DISABLE);
		DMA_ChannelEnable(serialx->txChannel, DISABLE);
		serialx->DMApacket.status |= txDone;
		serialx->DMApacket.status &= (~txBusy);
		serialx->DMApacket.txBufferSize = 0;
	}
}
/*
 *Input: SerialHandle
 *output: 1 byte of read
 */
char Serial_getc(SerialHandle_s* serialx)
{
	return serialx->packet.rxBuffer[serialx->packet.rxBufferSize++];
}
/*
Input: SerialHandle,  rxBuffer pointer, bytesOfread pointer
ouput: pointer of rxBuffer
*/
char* Serial_gets(SerialHandle_s* serialx)
{
	return (char*)(serialx->packet.rxBuffer);
}
// serialHandle[serial].packet.rxBuffer
/*
Input: SerialHandle,  rxBuffer pointer, bytesOfread pointer, bytes to read
ouput: pointer of rxBuffer
*/
char Serial_get(SerialHandle_s* serialx, uint16_t byteIndex)
{
	if (byteIndex >= USART_MAX_BUFFER_SIZE)
		return 0;
	return serialx->packet.rxBuffer[byteIndex - 1];
}
uint16_t IsSerialRxHasData(SerialHandle_s* serialx)
{
	if (serialx->DMApacket.status & rxDone)
	{
		return serialx->packet.rxBufferSize;
	}
	else
		return 0;
}
void uartPut(uint8_t* c, uint8_t len)
{
	Serial_put(&serialHandle[serial1], c, len);
	Serial_flush(&serialHandle[serial1]);
}
/**清空串口接收缓存 */
void Serial_Purge(SerialHandle_s* serialx)
{
	serialx->DMApacket.status &= ~rxDone;
	serialx->packet.rxBufferSize = 0;
	memset(serialx->packet.rxBuffer, 0, USART_MAX_BUFFER_SIZE);
}
void USART1_IRQHandler(void)
{
	Serial_IRQHandler(&serialHandle[serial]);
}
void USART2_IRQHandler(void)
{
	Serial_IRQHandler(&serialHandle[serial2]);
}
void USART3_IRQHandler(void)
{
	Serial_IRQHandler(&serialHandle[serial3]);
}
void UART4_IRQHandler(void)
{
	Serial_IRQHandler(&serialHandle[serial4]);
}
void UART5_IRQHandler(void)
{
	Serial_IRQHandler(&serialHandle[serial5]);
}

/* private function */
#define _ISDIGIT(c)  ((unsigned)((c) - '0') < 10)

/**
 * This function will duplicate a string.
 *
 * @param  n is the string to be duplicated.
 *
 * @param  base is support divide instructions value.
 *
 * @return the duplicated string pointer.
 */
#ifdef RT_KPRINTF_USING_LONGLONG
  int divide(long long *n, int base)
#else
  int divide(long *n, int base)
#endif /* RT_KPRINTF_USING_LONGLONG */
{
    int res;

    /* optimized for processor which does not support divide instructions. */
    if (base == 10)
    {
#ifdef RT_KPRINTF_USING_LONGLONG
        res = (int)(((unsigned long long)*n) % 10U);
        *n = (long long)(((unsigned long long)*n) / 10U);
#else
        res = (int)(((unsigned long)*n) % 10U);
        *n = (long)(((unsigned long)*n) / 10U);
#endif
    }
    else
    {
#ifdef RT_KPRINTF_USING_LONGLONG
        res = (int)(((unsigned long long)*n) % 16U);
        *n = (long long)(((unsigned long long)*n) / 16U);
#else
        res = (int)(((unsigned long)*n) % 16U);
        *n = (long)(((unsigned long)*n) / 16U);
#endif
    }

    return res;
}

  int skip_atoi(const char **s)
{
    int i = 0;
    while (_ISDIGIT(**s))
        i = i * 10 + *((*s)++) - '0';

    return i;
}

#define ZEROPAD     (1 << 0)    /* pad with zero */
#define SIGN        (1 << 1)    /* unsigned/signed long */
#define PLUS        (1 << 2)    /* show plus */
#define SPACE       (1 << 3)    /* space if plus */
#define LEFT        (1 << 4)    /* left justified */
#define SPECIAL     (1 << 5)    /* 0x */
#define LARGE       (1 << 6)    /* use 'ABCDEF' instead of 'abcdef' */
#define RT_PRINTF_PRECISION
static char *print_number(char *buf,
                          char *end,
#ifdef RT_KPRINTF_USING_LONGLONG
                          long long  num,
#else
                          long  num,
#endif /* RT_KPRINTF_USING_LONGLONG */
                          int   base,
                          int   s,
#ifdef RT_PRINTF_PRECISION
                          int   precision,
#endif /* RT_PRINTF_PRECISION */
                          int   type)
{
    char c, sign;
#ifdef RT_KPRINTF_USING_LONGLONG
    char tmp[32];
#else
    char tmp[16];
#endif /* RT_KPRINTF_USING_LONGLONG */
    int precision_bak = precision;
    const char *digits;
    static const char small_digits[] = "0123456789abcdef";
    static const char large_digits[] = "0123456789ABCDEF";
    int i, size;

    size = s;

    digits = (type & LARGE) ? large_digits : small_digits;
    if (type & LEFT)
        type &= ~ZEROPAD;

    c = (type & ZEROPAD) ? '0' : ' ';

    /* get sign */
    sign = 0;
    if (type & SIGN)
    {
        if (num < 0)
        {
            sign = '-';
            num = -num;
        }
        else if (type & PLUS)
            sign = '+';
        else if (type & SPACE)
            sign = ' ';
    }

#ifdef RT_PRINTF_SPECIAL
    if (type & SPECIAL)
    {
        if (base == 16)
            size -= 2;
        else if (base == 8)
            size--;
    }
#endif /* RT_PRINTF_SPECIAL */

    i = 0;
    if (num == 0)
        tmp[i++] = '0';
    else
    {
        while (num != 0)
            tmp[i++] = digits[divide(&num, base)];
    }

#ifdef RT_PRINTF_PRECISION
    if (i > precision)
        precision = i;
    size -= precision;
#else
    size -= i;
#endif /* RT_PRINTF_PRECISION */

    if (!(type & (ZEROPAD | LEFT)))
    {
        if ((sign) && (size > 0))
            size--;

        while (size-- > 0)
        {
            if (buf < end)
                *buf = ' ';
            ++ buf;
        }
    }

    if (sign)
    {
        if (buf < end)
        {
            *buf = sign;
        }
        -- size;
        ++ buf;
    }

#ifdef RT_PRINTF_SPECIAL
    if (type & SPECIAL)
    {
        if (base == 8)
        {
            if (buf < end)
                *buf = '0';
            ++ buf;
        }
        else if (base == 16)
        {
            if (buf < end)
                *buf = '0';
            ++ buf;
            if (buf < end)
            {
                *buf = type & LARGE ? 'X' : 'x';
            }
            ++ buf;
        }
    }
#endif /* RT_PRINTF_SPECIAL */

    /* no align to the left */
    if (!(type & LEFT))
    {
        while (size-- > 0)
        {
            if (buf < end)
                *buf = c;
            ++ buf;
        }
    }

#ifdef RT_PRINTF_PRECISION
    while (i < precision--)
    {
        if (buf < end)
            *buf = '0';
        ++ buf;
    }
#endif /* RT_PRINTF_PRECISION */

    /* put number in the temporary buffer */
    while (i-- > 0 && (precision_bak != 0))
    {
        if (buf < end)
            *buf = tmp[i];
        ++ buf;
    }

    while (size-- > 0)
    {
        if (buf < end)
            *buf = ' ';
        ++ buf;
    }

    return buf;
}

/**
 * This function will fill a formatted string to buffer.
 *
 * @param  buf is the buffer to save formatted string.
 *
 * @param  size is the size of buffer.
 *
 * @param  fmt is the format parameters.
 *
 * @param  args is a list of variable parameters.
 *
 * @return The number of characters actually written to buffer.
 */
int rt_vsnprintf(char *buf, int32_t size, const char *fmt, va_list args)
{
#ifdef RT_KPRINTF_USING_LONGLONG
    unsigned long long num;
#else
    uint32_t num;
#endif /* RT_KPRINTF_USING_LONGLONG */
    int i, len;
    char *str, *end, c;
    const char *s;

    uint8_t base;            /* the base of number */
    uint8_t flags;           /* flags to print number */
    uint8_t qualifier;       /* 'h', 'l', or 'L' for integer fields */
    int32_t field_width;     /* width of output field */

#ifdef RT_PRINTF_PRECISION
    int precision;      /* min. # of digits for integers and max for a string */
#endif /* RT_PRINTF_PRECISION */

    str = buf;
    end = buf + size;

    /* Make sure end is always >= buf */
    if (end < buf)
    {
        end  = ((char *) - 1);
        size = end - buf;
    }

    for (; *fmt ; ++fmt)
    {
        if (*fmt != '%')
        {
            if (str < end)
                *str = *fmt;
            ++ str;
            continue;
        }

        /* process flags */
        flags = 0;

        while (1)
        {
            /* skips the first '%' also */
            ++ fmt;
            if (*fmt == '-') flags |= LEFT;
            else if (*fmt == '+') flags |= PLUS;
            else if (*fmt == ' ') flags |= SPACE;
            else if (*fmt == '#') flags |= SPECIAL;
            else if (*fmt == '0') flags |= ZEROPAD;
            else break;
        }

        /* get field width */
        field_width = -1;
        if (_ISDIGIT(*fmt)) field_width = skip_atoi(&fmt);
        else if (*fmt == '*')
        {
            ++ fmt;
            /* it's the next argument */
            field_width = va_arg(args, int);
            if (field_width < 0)
            {
                field_width = -field_width;
                flags |= LEFT;
            }
        }

#ifdef RT_PRINTF_PRECISION
        /* get the precision */
        precision = -1;
        if (*fmt == '.')
        {
            ++ fmt;
            if (_ISDIGIT(*fmt)) precision = skip_atoi(&fmt);
            else if (*fmt == '*')
            {
                ++ fmt;
                /* it's the next argument */
                precision = va_arg(args, int);
            }
            if (precision < 0) precision = 0;
        }
#endif /* RT_PRINTF_PRECISION */
        /* get the conversion qualifier */
        qualifier = 0;
#ifdef RT_KPRINTF_USING_LONGLONG
        if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
#else
        if (*fmt == 'h' || *fmt == 'l')
#endif /* RT_KPRINTF_USING_LONGLONG */
        {
            qualifier = *fmt;
            ++ fmt;
#ifdef RT_KPRINTF_USING_LONGLONG
            if (qualifier == 'l' && *fmt == 'l')
            {
                qualifier = 'L';
                ++ fmt;
            }
#endif /* RT_KPRINTF_USING_LONGLONG */
        }

        /* the default base */
        base = 10;

        switch (*fmt)
        {
        case 'c':
            if (!(flags & LEFT))
            {
                while (--field_width > 0)
                {
                    if (str < end) *str = ' ';
                    ++ str;
                }
            }

            /* get character */
            c = (uint8_t)va_arg(args, int);
            if (str < end) *str = c;
            ++ str;

            /* put width */
            while (--field_width > 0)
            {
                if (str < end) *str = ' ';
                ++ str;
            }
            continue;

        case 's':
            s = va_arg(args, char *);
            if (!s) s = "(NULL)";

            for (len = 0; (len != field_width) && (s[len] != '\0'); len++);
#ifdef RT_PRINTF_PRECISION
            if (precision > 0 && len > precision) len = precision;
#endif /* RT_PRINTF_PRECISION */

            if (!(flags & LEFT))
            {
                while (len < field_width--)
                {
                    if (str < end) *str = ' ';
                    ++ str;
                }
            }

            for (i = 0; i < len; ++i)
            {
                if (str < end) *str = *s;
                ++ str;
                ++ s;
            }

            while (len < field_width--)
            {
                if (str < end) *str = ' ';
                ++ str;
            }
            continue;

        case 'p':
            if (field_width == -1)
            {
                field_width = sizeof(void *) << 1;
                flags |= ZEROPAD;
            }
#ifdef RT_PRINTF_PRECISION
            str = print_number(str, end,
                               (long)va_arg(args, void *),
                               16, field_width, precision, flags);
#else
            str = print_number(str, end,
                               (long)va_arg(args, void *),
                               16, field_width, flags);
#endif /* RT_PRINTF_PRECISION */
            continue;

        case '%':
            if (str < end) *str = '%';
            ++ str;
            continue;

        /* integer number formats - set up the flags and "break" */
        case 'o':
            base = 8;
            break;

        case 'X':
            flags |= LARGE;
        case 'x':
            base = 16;
            break;

        case 'd':
        case 'i':
            flags |= SIGN;
        case 'u':
            break;

        default:
            if (str < end) *str = '%';
            ++ str;

            if (*fmt)
            {
                if (str < end) *str = *fmt;
                ++ str;
            }
            else
            {
                -- fmt;
            }
            continue;
        }

#ifdef RT_KPRINTF_USING_LONGLONG
        if (qualifier == 'L') num = va_arg(args, long long);
        else if (qualifier == 'l')
#else
        if (qualifier == 'l')
#endif /* RT_KPRINTF_USING_LONGLONG */
        {
            num = va_arg(args, uint32_t);
            if (flags & SIGN) num = (int32_t)num;
        }
        else if (qualifier == 'h')
        {
            num = (uint16_t)va_arg(args, int32_t);
            if (flags & SIGN) num = (int16_t)num;
        }
        else
        {
            num = va_arg(args, uint32_t);
            if (flags & SIGN) num = (int32_t)num;
        }
#ifdef RT_PRINTF_PRECISION
        str = print_number(str, end, num, base, field_width, precision, flags);
#else
        str = print_number(str, end, num, base, field_width, flags);
#endif /* RT_PRINTF_PRECISION */
    }

    if (size > 0)
    {
        if (str < end) *str = '\0';
        else
        {
            end[-1] = '\0';
        }
    }

    /* the trailing null byte doesn't count towards the total
    * ++str;
    */
    return str - buf;
}

/**
 * This function will fill a formatted string to buffer.
 *
 * @param  buf is the buffer to save formatted string.
 *
 * @param  size is the size of buffer.
 *
 * @param  fmt is the format parameters.
 *
 * @return The number of characters actually written to buffer.
 */
int rt_snprintf(char *buf, int32_t size, const char *fmt, ...)
{
    int32_t n;
    va_list args;

    va_start(args, fmt);
    n = rt_vsnprintf(buf, size, fmt, args);
    va_end(args);

    return n;
}


/**
 * This function will fill a formatted string to buffer.
 *
 * @param  buf is the buffer to save formatted string.
 *
 * @param  format is the format parameters.
 *
 * @param  arg_ptr is a list of variable parameters.
 *
 * @return The number of characters actually written to buffer.
 */
int rt_vsprintf(char *buf, const char *format, va_list arg_ptr)
{
    return rt_vsnprintf(buf, (int32_t) - 1, format, arg_ptr);
}


/**
 * This function will fill a formatted string to buffer
 *
 * @param  buf the buffer to save formatted string.
 *
 * @param  format is the format parameters.
 *
 * @return The number of characters actually written to buffer.
 */
int rt_sprintf(char *buf, const char *format, ...)
{
    int32_t n;
    va_list arg_ptr;

    va_start(arg_ptr, format);
    n = rt_vsprintf(buf, format, arg_ptr);
    va_end(arg_ptr);

    return n;
}
#define RT_CONSOLEBUF_SIZE 64
/**
 * This function will print a formatted string on system console.
 *
 * @param fmt is the format parameters.
 *
 * @return The number of characters actually written to buffer.
 */
int rt_kprintf(const char *fmt, ...)
{
    va_list args;
    int16_t length;
    static char rt_log_buf[RT_CONSOLEBUF_SIZE];

    va_start(args, fmt);
    /* the return value of vsnprintf is the number of bytes that would be
     * written to buffer had if the size of the buffer been sufficiently
     * large excluding the terminating null byte. If the output string
     * would be larger than the rt_log_buf, we have to adjust the output
     * length. */
    length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args);
    if (length > RT_CONSOLEBUF_SIZE - 1)
        length = RT_CONSOLEBUF_SIZE - 1;
	Serial_put(&serialHandle[serial], (uint8_t*)rt_log_buf, length);
	Serial_flush(&serialHandle[serial]);
    va_end(args);
    return length;
}
